package cn.tang.tframe.sdm.web.exception;

import cn.tang.tframe.common.base.BaseResult;
import cn.tang.tframe.common.base.ResultCode;
import cn.tang.tframe.common.exception.BaseException;
import cn.tang.tframe.common.exception.BaseRtmException;
import cn.tang.tframe.common.utils.lang.StringUtils;
import cn.tang.tframe.sdm.utils.BeanValidators;
import cn.tang.tframe.sdm.utils.JsonMapper;
import cn.tang.tframe.sdm.utils.MediaTypes;
import cn.tang.tframe.sdm.utils.RequestUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.multipart.MaxUploadSizeExceededException;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
import org.springframework.web.servlet.view.UrlBasedViewResolver;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.ConstraintViolationException;
import java.util.HashMap;
import java.util.Map;

/**
 * 自定义ExceptionHandler，
 * 
 * @author tanghc
 */
// 会被Spring-MVC自动扫描，但又不属于Controller的annotation。
@ControllerAdvice
public class RestExceptionHandler extends ResponseEntityExceptionHandler {
	private static Logger logger = LoggerFactory.getLogger(RestExceptionHandler.class);

	/**
	 * 处理JSR311 Validation异常.
	 */
	@ExceptionHandler(value = { ConstraintViolationException.class })
	public final Object handleException(ConstraintViolationException ex, WebRequest request,
			HttpServletRequest httpRequest, HttpServletResponse httpResponse) {
		Map<String, String> errors = BeanValidators.extractPropertyAndMessage(ex.getConstraintViolations());
		return processException(ex, ResultCode.OTHER.getCode(), JsonMapper.getInstance().toJson(errors), request,
				httpRequest, httpResponse);
	}

	/**
	 * 处理BaseCustomRtmException异常.
	 */
	@ExceptionHandler(value = { BaseRtmException.class })
	public final Object handleBaseCustomRtmException(BaseRtmException ex, WebRequest request,
			HttpServletRequest httpRequest, HttpServletResponse httpResponse) {
		return processException(ex, ResultCode.OTHER.getCode(), ex.getMessage(), request, httpRequest, httpResponse);
	}

	/**
	 * 处理BaseCustomRtmException异常.
	 */
	@ExceptionHandler(value = { BaseException.class })
	public final Object handleBaseException(BaseException ex, WebRequest request, HttpServletRequest httpRequest,
			HttpServletResponse httpResponse) {
		return processException(ex, ResultCode.OTHER.getCode(), ex.getMessage(), request, httpRequest, httpResponse);
	}

	/**
	 * 处理所有未分类型的异常.
	 */
	@ExceptionHandler(value = { Exception.class })
	public final Object handleException1(Exception ex, WebRequest request, HttpServletRequest httpRequest,
			HttpServletResponse httpResponse) {
		String stackTraceStr = "请求失败";
		return processException(ex, ResultCode.OTHER.getCode(), stackTraceStr, request, httpRequest, httpResponse);

	}

//	/**
//	 * 处理所有未分类型的异常.
//	 */
//	@ExceptionHandler(value = { UnauthorizedException.class })
//	public final Object handleException2(UnauthorizedException ex, WebRequest request, HttpServletRequest httpRequest,
//			HttpServletResponse httpResponse) {
//		String stackTraceStr = "没有权限访问";
//		return processException(ex, ResultCode.OTHER.getCode(), stackTraceStr, request, httpRequest, httpResponse);
//
//	}

	/**
	 * 处理上传文件过大异常
	 */
	@ExceptionHandler(value = { MaxUploadSizeExceededException.class })
	public final Object maxSizeException(MaxUploadSizeExceededException ex, WebRequest request,
			HttpServletRequest httpRequest, HttpServletResponse httpResponse) {
		String stackTraceStr = "文件上传不能超过" + this.getFileMB(ex.getMaxUploadSize());
		return processException(ex, ResultCode.OTHER.getCode(), stackTraceStr, request, httpRequest, httpResponse);
	}

	private Object processException(Exception e, String statusCode, String message, WebRequest request,
			HttpServletRequest httpRequest, HttpServletResponse httpResponse) {
		logger.warn("controller exception: requestUri={},msg={}", httpRequest.getRequestURI(), e.getMessage());
		boolean ajaxRequest = RequestUtils.isAjaxRequest(httpRequest);
		if (!ajaxRequest) {
			logger.error("error redirect to 500.jsp");
			Map<String, Object> model = new HashMap<>();
			model.put("message", StringUtils.isNotBlank(message) ? message : "操作失败");
			return new ModelAndView(UrlBasedViewResolver.FORWARD_URL_PREFIX + "/common/error/500.jsp", model);
		}
		String rbJson = JsonMapper.getInstance().toJson(BaseResult.fail(message));
		HttpHeaders headers = new HttpHeaders();
		headers.setContentType(MediaType.parseMediaType(MediaTypes.TEXT_PLAIN_UTF_8));
		logger.warn("controller exception: requestUri={},msg={},result={}", httpRequest.getRequestURI(),
				e.getMessage(), rbJson);
		return this.handleExceptionInternal(e, rbJson, headers, HttpStatus.OK, request);
	}

	/**
	 * 计算文件MB大小
	 *
	 * @param byteFile
	 *            字节数
	 * @return
	 */
	private String getFileMB(long byteFile) {
		if (byteFile == 0) {
			return "0MB";
		}
		long mb = 1024 * 1024;
		return "" + byteFile / mb + "MB";
	}
}
